/**
 * Get scrolled top
 * @return scrolled top
 */
export function getScrollTop(): number {
  let scroll_top = 0
  if (document.documentElement.scrollTop) {
    scroll_top = document.documentElement.scrollTop
  } else if (document.body) {
    scroll_top = document.body.scrollTop
  }
  return scroll_top
}

/**
 * Determine whether the dom element is in the visible view
 * @param dom determine targets
 * @return yes or no
 */
export function isVisible(dom: HTMLElement) {
  let scrollH = getScrollTop(),
    winH = document.documentElement.clientHeight || document.body.clientHeight,
    top = dom.offsetTop
  return top < winH + scrollH
}

/**
 * debounce function
 * @template T fn type limit is a function type
 * @param fn function to be wrapped
 * @param delay debounce time
 * @return debounced fn
 */
export function debounce<T extends (...args: any) => void>(fn: T, delay = 200) {
  let timer: number
  return function (...args: Parameters<T>) {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => fn.apply(null, args), delay)
  }
}

/**
 * bind type event listener and when location.pathname isn't equiv path,
 * auto remove event listener
 * @param path no equiv this path will remove this listener
 * @param type addEventListener type
 * @param fn event handler
 */
export function bindAutoRemove<T extends keyof WindowEventMap>(
  path: string,
  type: T,
  fn: (ev: WindowEventMap[T]) => void,
) {
  const handlerListener = (ev: WindowEventMap[T]) => {
    if (location.pathname !== path)
      window.removeEventListener(type, handlerListener)
    fn(ev)
  }
  window.addEventListener(type, handlerListener)
}
